/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufc.quixada.adrs.service;

import br.ufc.quixada.adrs.dao.ProdutorDAO;
import br.ufc.quixada.adrs.model.Adrs;
import br.ufc.quixada.adrs.model.Contato;
import br.ufc.quixada.adrs.model.Prazo;
import br.ufc.quixada.adrs.model.Produtor;
import br.ufc.quixada.adrs.util.Msg;
import br.ufc.quixada.adrs.util.UtilAdrs;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.LoggerFactory;

/**
 *
 * @author franklin barroso
 */
public class ProdutorService {

    public static final Comparator<Produtor> comparadorPorMunicipioENome = new Comparator<Produtor>() {

        public int compare(Produtor a, Produtor b) {
            return (a.getUsuario().getEndereco().getMunicipio().getNome() + a.getUsuario().getNome()).compareTo(
                    b.getUsuario().getEndereco().getMunicipio().getNome() + b.getUsuario().getNome());
        }
    };
    public static final Comparator<Produtor> comparadorPorNome = new Comparator<Produtor>() {

        public int compare(Produtor a, Produtor b) {
            return a.getUsuario().getNome().compareTo(b.getUsuario().getNome());
        }
    };
    public static final Comparator<Contato> comparadorContatosPorId = new Comparator<Contato>() {

        public int compare(Contato a, Contato b) {
            return a.getId().compareTo(b.getId());
        }
    };
    public static final Comparator<Produtor> comparadorPorAdrsId = new Comparator<Produtor>() {

        public int compare(Produtor a, Produtor b) {
            if (a.getAdrs() == null) {
                return 1;
            }
            if (b.getAdrs() == null) {
                return 0;
            }
            return a.getAdrs().getId().compareTo(b.getAdrs().getId());
        }
    };
    public static final Comparator<Produtor> comparadorPorDataExclusao = new Comparator<Produtor>() {

        public int compare(Produtor b, Produtor a) {
            if (b.getDataExclusao() == null) {
                return 1;
            }
            if (a.getDataExclusao() == null) {
                return 0;
            }
            return a.getDataExclusao().compareTo(b.getDataExclusao());
        }
    };
    public static final Comparator comparadorPorDataVisita = new Comparator<Produtor>() {

        public int compare(Produtor o1, Produtor o2) {
            if (o2.getUltimaVisita() == null) {
                return 0;
            }
            if (o1.getUltimaVisita() == null) {
                return 1;
            }
            return o2.getUltimaVisita().getData().compareTo(o1.getUltimaVisita().getData());
        }
    };
    private final ProdutorDAO produtorDao = new ProdutorDAO();

    public boolean insertProdutor(Produtor produtor) {
        try {
            UtilAdrs.upperCase(produtor);
            produtorDao.insert(produtor);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public boolean updateProdutor(Produtor produtor) {
        try {
            UtilAdrs.upperCase(produtor);
            produtorDao.update(produtor);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public boolean reativarContaProdutor(Produtor produtor) {
        try {
            produtorDao.reativarProdutor(produtor);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public boolean vincularAdrs(Produtor produtor, Adrs adrs) {
        try {
            produtor.setAdrs(adrs);
            produtorDao.vincularAdrs(produtor);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public boolean deleteProdutor(Produtor produtor) {
        try {
            produtorDao.delete(produtor);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }

    public Produtor getProdutorByUsuarioId(Long id) {
        try {
            Produtor produtor = produtorDao.getByUsuarioId(id);
            return produtor;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public Produtor getProdutorByUsuarioIdToAtivarConta(Long id) {
        try {
            Produtor produtor = produtorDao.getByUsuarioIdToAtivarConta(id);
            return produtor;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public Produtor getProdutorById(Long id) {
        try {
            Produtor produtor = produtorDao.getById(id);
            if (produtor == null) {
                return produtor;
            }
            List<Contato> contatos = produtor.getUsuario().getContatos();
            Collections.sort(contatos, comparadorContatosPorId);
            produtor.getUsuario().setContatos(contatos);
            return produtor;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public List<Produtor> getProdutoresByAdrsId(Long id) {
        try {
            List<Produtor> produtores = produtorDao.getByAdrsId(id);
            Collections.sort(produtores, comparadorPorNome);
            if (produtores != null && !produtores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(produtores);
            }
            return produtores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public List<Produtor> getProdutoresVinculados() {
        try {
            List<Produtor> produtores = produtorDao.getVinculados();
            Collections.sort(produtores, comparadorPorNome);
            if (produtores != null && !produtores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(produtores);
            }
            return produtores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public List<Produtor> searchProdutoresByNome(String nome) {
        try {
            nome = "%" + nome + "%";
            List<Produtor> produtores = produtorDao.searchByNome(nome);
            Collections.sort(produtores, comparadorPorNome);
            if (produtores != null && !produtores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(produtores);
            }
            return produtores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public List<Produtor> searchProdutoresByLocalidade(String localidade) {
        try {
            localidade = "%" + localidade + "%";
            List<Produtor> produtores = produtorDao.searchByLocalidade(localidade);
            Collections.sort(produtores, comparadorPorMunicipioENome);
            if (produtores != null && !produtores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(produtores);
            }
            return produtores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public List<Produtor> getProdutoresForaPrazoSanitario(Prazo prazo, Adrs adrs) {
        try {
            Map hm = elaborarDadosParaConsulta(adrs, prazo);
            List<Produtor> listaProdutores = produtorDao.getProdutoresSemQuestSanitarioByAdrsPrazo(hm);
            if (listaProdutores != null || !listaProdutores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(listaProdutores);
                //return produtorDao.getProdutoresSemQuestSanitarioByAdrsPrazo(hm);
            }
            return listaProdutores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public List<Produtor> getProdutoresForaPrazoQualitativo(Prazo prazo, Adrs adrs) {
        try {
            Map hm = elaborarDadosParaConsulta(adrs, prazo);
            List<Produtor> listaProdutores = produtorDao.getProdutoresSemQuestQualitativoByAdrsPrazo(hm);
            if (listaProdutores != null || !listaProdutores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(listaProdutores);
                //return produtorDao.getProdutoresSemQuestQualitativoByAdrsPrazo(hm);
            }
            return listaProdutores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    public List<Produtor> getProdutoresForaPrazoQuantitativo(Prazo prazo, Adrs adrs) {
        try {
            Map hm = elaborarDadosParaConsulta(adrs, prazo);
            List<Produtor> listaProdutores = produtorDao.getProdutoresSemQuestQuantitativoByAdrsPrazo(hm);
            if (listaProdutores != null || !listaProdutores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(listaProdutores);
                //return produtorDao.getProdutoresSemQuestQuantitativoByAdrsPrazo(hm);
            }
            return listaProdutores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
        }
        return null;
    }

    private Map elaborarDadosParaConsulta(Adrs adrs, Prazo prazo) {
        Map hm = new HashMap(4);
        hm.put("idAdrs", adrs.getId());
        hm.put("idAdrs2", adrs.getId());
        hm.put("dataInicio", prazo.getInicio());
        hm.put("dataFim", prazo.getFim());
        return hm;
    }

    public List<Produtor> getAllProdutores() {
        try {
            List<Produtor> produtores = produtorDao.getAll();
            Collections.sort(produtores, comparadorPorMunicipioENome);
            if (produtores != null && !produtores.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(produtores);
            }
            return produtores;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }

    }

    public List<List<Produtor>> getProdutoresExcluidos() {
        try {
            List<List<Produtor>> excluidos = new ArrayList<List<Produtor>>();
            List<Produtor> produtores = produtorDao.getExcluidos();
            //processamento de separação por adrs e ordenação por data de exclusao
            Collections.sort(produtores, comparadorPorAdrsId);
            int atual, ultimo;
            Produtor p = null;
            for (atual = 1, ultimo = 0; atual < produtores.size(); atual++) {
                p = produtores.get(atual);
                if (!p.getAdrs().getId().equals(produtores.get(ultimo).getAdrs().getId())) {
                    excluidos.add(new ArrayList(produtores.subList(ultimo, atual)));
                    ultimo = atual;
                }
            }
            excluidos.add(new ArrayList(produtores.subList(ultimo, produtores.size())));
            for (List<Produtor> a : excluidos) {
                Collections.sort(a, comparadorPorDataExclusao);
            }
            return excluidos;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }
    
    public List<List<Produtor>> getAllProdutoresDivididosPorAdrs() {
        try {
            List<List<Produtor>> excluidos = new ArrayList<List<Produtor>>();
            List<Produtor> produtores = produtorDao.getAll();
            //processamento de separação por adrs e ordenação por municipio e nome
            Collections.sort(produtores, comparadorPorAdrsId);
            int atual, ultimo;
            Produtor p = null;
            for (atual = 1, ultimo = 0; atual < produtores.size(); atual++) {
                p = produtores.get(atual);
                if (!p.getAdrs().getId().equals(produtores.get(ultimo).getAdrs().getId())) {
                    excluidos.add(new ArrayList(produtores.subList(ultimo, atual)));
                    ultimo = atual;
                }
            }
            excluidos.add(new ArrayList(produtores.subList(ultimo, produtores.size())));
            for (List<Produtor> a : excluidos) {
                Collections.sort(a, comparadorPorMunicipioENome);
            }
            return excluidos;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public List<Produtor> getByEstadoId(Long id) {
        try {
            List<Produtor> listaProdutor = produtorDao.getByEstadoId(id);
            if (listaProdutor == null || listaProdutor.isEmpty()) {
                return null;
            }
            Collections.sort(listaProdutor, comparadorPorMunicipioENome);
            if (listaProdutor != null || !listaProdutor.isEmpty()) {
                UtilAdrs.marcarProdutoresNovos(listaProdutor);
            }
            return listaProdutor;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public List<Produtor> getByMunicipioId(Long id) {
        try {
            List<Produtor> listaProdutor = produtorDao.getByMunicipioId(id);
            if (listaProdutor == null || listaProdutor.isEmpty()) {
                return null;
            } else {
                Collections.sort(listaProdutor, comparadorPorMunicipioENome);
                if (listaProdutor != null || !listaProdutor.isEmpty()) {
                    UtilAdrs.marcarProdutoresNovos(listaProdutor);
                }
                return listaProdutor;
            }
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public Produtor getProdutorByConjugeCpf(String cpf) {
        try {
            Produtor produtor = produtorDao.getByConjugeCpf(UtilAdrs.desFormataCPF(cpf));
            if (produtor == null) {
                return produtor;
            }
            List<Contato> contatos = produtor.getUsuario().getContatos();
            Collections.sort(contatos, comparadorContatosPorId);
            produtor.getUsuario().setContatos(contatos);
            return produtor;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public Produtor searchProdutorByCpf(String cpf) {
        try {
            Produtor produtor = produtorDao.searchByCPF(UtilAdrs.desFormataCPF(cpf));
            if (produtor == null) {
                return produtor;
            }
            List<Contato> contatos = produtor.getUsuario().getContatos();
            Collections.sort(contatos, comparadorContatosPorId);
            produtor.getUsuario().setContatos(contatos);
            if (UtilAdrs.diferencaDatas(produtor)) {
                UtilAdrs.destacarProdutor(produtor);
            }
            return produtor;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public Produtor getProdutorByDap(String dap) {
        try {
            Produtor produtor = produtorDao.getByDap(dap);
            if (produtor == null) {
                return produtor;
            }
            List<Contato> contatos = produtor.getUsuario().getContatos();
            Collections.sort(contatos, comparadorContatosPorId);
            produtor.getUsuario().setContatos(contatos);
            return produtor;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return null;
        }
    }

    public String validaParaInsercao(Produtor p) {
        UsuarioService us = new UsuarioService();
        String userValidation = us.validaParaInsercao(p.getUsuario());

        if (!userValidation.equals(Msg.OK) && !userValidation.equals(Msg.REQUIRED_EMAIL_FIELD)) {
            return userValidation;
        }

        if (p.getConjugeCpf() != null && !p.getConjugeCpf().isEmpty()) {
            if (!us.validaCPF(p.getConjugeCpf())) {
                return Msg.INPUT_ERROR_INVALID_CONJUGE_CPF;
            }
        }

        if (getProdutorByConjugeCpf(p.getConjugeCpf()) != null) {
            return Msg.EXISTANT_CONJUGE_CPF;
        }
        if (getProdutorByDap(p.getDAP()) != null) {
            return Msg.EXISTANT_DAP;
        }
        return Msg.OK;
    }

    public String validaParaEdicao(Produtor p) {
        UsuarioService us = new UsuarioService();
        String userValidation = us.validaParaEdicao(p.getUsuario());

        if (!userValidation.equals(Msg.OK) && !userValidation.equals(Msg.REQUIRED_EMAIL_FIELD)) {
            return userValidation;
        }

        if (p.getConjugeCpf() != null && !p.getConjugeCpf().isEmpty()) {
            if (!us.validaCPF(p.getConjugeCpf())) {
                return Msg.INPUT_ERROR_INVALID_CONJUGE_CPF;
            }
        }

        Produtor prod = getProdutorByConjugeCpf(p.getConjugeCpf());
        if (prod != null && !prod.getId().equals(p.getId())) {
            return Msg.EXISTANT_CONJUGE_CPF;
        } else {
            prod = null;
        }
        prod = getProdutorByDap(p.getDAP());
        if (prod != null && !prod.getId().equals(p.getId())) {
            return Msg.EXISTANT_DAP;
        } else {
            prod = null;
        }
        return Msg.OK;
    }

    public boolean transferirProdutoresAdrs(Adrs antigo, Adrs novo) {
        Map hm = new HashMap(2);
        hm.put("idAdrsNovo", novo.getId());
        hm.put("idAdrsAntigo", antigo.getId());
        try {
            produtorDao.transferirProdutoresAdrs(hm);
            return true;
        } catch (SQLException ex) {
            LoggerFactory.getLogger(this.getClass()).error(Msg.EXCEPTION_MESSAGE, this.getClass().getSimpleName(), ex);
            return false;
        }
    }
}
